package com.wn.cloud.rule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @FileName: MyRoundRule
 * @Description: 自定义ribbon负载均衡策略
 * @Author: MaWenHao
 * @Created: 2020/3/11 - 0:20
 * @Version: V1.0
 * @Company: 东方微银科技（北京）有限公司
 */
@Slf4j
public class MyRoundRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;

    private AtomicInteger currentServerCount;

    public MyRoundRule() {
        nextServerCyclicCounter = new AtomicInteger(1);
        currentServerCount = new AtomicInteger(0);
    }

    public MyRoundRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

    /**
     * 轮询：1号执行三次，2号执行1次
     *
     * @param lb
     * @param key
     * @return
     */
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            // 获取所有的server
            List<Server> allServers = lb.getAllServers();
            // 获取所有server的数量
            int serverCount = allServers.size();

            if (serverCount == 0) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount);
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

    private int incrementAndGetModulo(int modulo) {
        while (true) {
            int currentCount = currentServerCount.get();
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;

            // 大于等于3
            if (currentCount > 2) {
                if (currentServerCount.compareAndSet(currentCount, 0)
                        && nextServerCyclicCounter.compareAndSet(current, next)) {
                    return current;
                }
                continue;
            }

            // 等于2
            if (currentCount == 2) {
                if (currentServerCount.compareAndSet(currentCount, currentCount + 1)
                        && nextServerCyclicCounter.compareAndSet(current, next)) {
                    return current;
                }
                continue;
            }

            // 小于2
            if (currentServerCount.compareAndSet(currentCount, currentCount + 1)) {
                return current;
            }
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}
